package cn.tsinghua.wenjiesha.owfn;

import java.util.ArrayList;

class PetriNetException extends Exception{
	public PetriNetException(){}
	public PetriNetException(String msg){
		super(msg);
	}
}

enum PlaceType{
	start,
	end,
	incoming,
	outcoming,
	internal
}

/* class Petri Net
 * contain P->T matrix
 * T->P matrix
 * and a list of places and transitions
 * so the Petri Net is defined
 * */
public class PetriNet{
	private int pnum;
	private int tnum;
	private Place placeList[];
	private Transition transitionList[];
	private Matrix PTMatrix;
	private Matrix TPMatrix;
	public PetriNet(int pnum, int tnum){
		this.pnum = pnum;
		this.tnum = tnum;
		this.setPTMatrix(new Matrix(pnum, tnum));
		this.setTPMatrix(new Matrix(pnum, tnum));
		this.setPlaceList(new Place[pnum]);
		this.setTransitionList(new Transition[tnum]);
	}
	public State initState(){		
		return new State(pnum);
	}
	public State finalState() throws PetriNetException{
		State state = new State(pnum);
		for(int i = 0; i < placeList.length; i++){
			if(placeList[i].getType().compareTo(PlaceType.end) == 0){
				state.setTokenNum(i, 1);
				return state;
			}
		}
		throw new PetriNetException("No end state!");
	}
	// fire all possible transitions, and return the list of possible next states from current state
	public ArrayList<State> nextState(State state){
		ArrayList<State> stateList = new ArrayList<State>();
		for(int i = 0; i < tnum; i++){
			if(precondition(i, state)){
				State nState = nextState(i, state);
				if(!stateList.contains(nState))
					stateList.add(nState);
			}
		}
		return stateList;
	}
	// if the transition i can fire in state
	private boolean precondition(int i, State state) {
		// TODO Auto-generated method stub
		for(int pIndex = 0; pIndex < pnum; i++){
			if(state.getTokenNum(pIndex) < getPTMatrix().getTokenNum(pIndex, i))
				return false;
		}
		return true;
	}
	// what is the next state of current state, if transition i is fired
	private State nextState(int i, State state) {
		// TODO Auto-generated method stub
		State nState = new State(state);
		for(int pIndex = 0; pIndex < pnum; i++){
			nState.setTokenNum(pIndex, nState.getTokenNum(pIndex) - getPTMatrix().getTokenNum(pIndex, i) + getTPMatrix().getTokenNum(pIndex, i));
		}		
		return null;
	}
	public void setPlaceList(Place placeList[]) {
		this.placeList = placeList;
	}
	public Place[] getPlaceList() {
		return placeList;
	}
	public void setTransitionList(Transition transitionList[]) {
		this.transitionList = transitionList;
	}
	public Transition[] getTransitionList() {
		return transitionList;
	}
	public void setPTMatrix(Matrix pTMatrix) {
		PTMatrix = pTMatrix;
	}
	public Matrix getPTMatrix() {
		return PTMatrix;
	}
	public void setTPMatrix(Matrix tPMatrix) {
		TPMatrix = tPMatrix;
	}
	public Matrix getTPMatrix() {
		return TPMatrix;
	}
	
}

class State{	
	private int state[];
	public State(int pNum){
		this.state = new int[pNum];
		for(int i = 0; i < pNum; i++){
			state[i] = 0;
		}		
	}
	public State(State src){
		this.state = new int[src.getPNum()];
		for(int i = 0; i < state.length; i++){
			state[i] = src.getTokenNum(i);
		}
	}
	public State(int state[]){		
		this.state = state;
	}
	public int getTokenNum(int index){
		return state[index];
	}
	public int getPNum(){
		return state.length;
	}
	public boolean equals(Object input){
		if(this == input) return true;
		if(input == null || getClass() != input.getClass()) return false;
		for(int i = 0; i < state.length; i++){
			if(getTokenNum(i) != ((State)input).getTokenNum(i))
				return false;
		}
		return true;
	}
	public void setTokenNum(int index, int num){
		state[index] = num;
	}
}

class Transition{
	int tid;
	String name;
	public Transition(int tid, String name){
		this.tid = tid;
		this.name = name;
	}
}
class Place{
	private int pid;
	private PlaceType type;
	public Place(int pid, PlaceType type){
		this.pid = pid;
		this.setType(type);
	}
	public void setType(PlaceType type) {
		this.type = type;
	}
	public PlaceType getType() {
		return type;
	}
}
class Matrix{
	int matrix[][];
	public Matrix(int pnum, int tnum){
		this.matrix = new int[pnum][tnum];
	}
	public int getTokenNum(int i, int j){
		return matrix[i][j];
	}
}	
